import requests
import re
import json
import moviepy.editor
import os
import time
from pyquery import PyQuery as pq
from hashlib import md5
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains


class Chaojiying_Client(object):

    def __init__(self, username, password, soft_id):
        self.username = username
        password =  password.encode('utf8')
        self.password = md5(password).hexdigest()
        self.soft_id = soft_id
        self.base_params = {
            'user': self.username,
            'pass2': self.password,
            'softid': self.soft_id,
        }
        self.headers = {
            'Connection': 'Keep-Alive',
            'User-Agent': 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)',
        }

    def PostPic(self, im, codetype):
        """
        im: 图片字节
        codetype: 题目类型 参考 http://www.chaojiying.com/price.html
        """
        params = {
            'codetype': codetype,
        }
        params.update(self.base_params)
        files = {'userfile': ('ccc.jpg', im)}
        r = requests.post('http://upload.chaojiying.net/Upload/Processing.php', data=params, files=files, headers=self.headers)
        return r.json()

    def PostPic_base64(self, base64_str, codetype):
        """
        im: 图片字节
        codetype: 题目类型 参考 http://www.chaojiying.com/price.html
        """
        params = {
            'codetype': codetype,
            'file_base64':base64_str
        }
        params.update(self.base_params)
        r = requests.post('http://upload.chaojiying.net/Upload/Processing.php', data=params, headers=self.headers)
        return r.json()

    def ReportError(self, im_id):
        """
        im_id:报错题目的图片ID
        """
        params = {
            'id': im_id,
        }
        params.update(self.base_params)
        r = requests.post('http://upload.chaojiying.net/Upload/ReportError.php', data=params, headers=self.headers)
        return r.json()


if __name__ == '__main__':
    # 创建Chrome浏览器对象
    browser = webdriver.Chrome()

    # 访问登录网站
    browser.get('https://passport.bilibili.com/login')

    # 点击账号并输入
    browser.find_element(By.XPATH, '//*[@id="login-username"]').click()
    browser.find_element(By.XPATH, '//*[@id="login-username"]').send_keys('B站账号')
    # 点击密码并输入
    browser.find_element(By.XPATH, '//*[@id="login-passwd"]').click()
    browser.find_element(By.XPATH, '//*[@id="login-passwd"]').send_keys('B站密码')
    time.sleep(1)
    # 点击登录
    browser.find_element(By.XPATH, '//*[@id="geetest-wrap"]/div/div[5]/a[1]').click()
    time.sleep(1)

    # 保存验证码截图
    yanzhengma = browser.find_element(By.XPATH, '/html/body/div[2]/div[2]/div[6]')
    yanzhengma.screenshot('./b.png')
    print('已保存验证码图片')
    time.sleep(2)

    # 获取验证码页面的左上角的坐标
    location = yanzhengma.location
    print(location)
    # print(location['x'])
    # print(type(location['x']))

    print('发送破解验证码请求')
    # 使用超级鹰获取坐标点
    chaojiying = Chaojiying_Client('超级鹰账号', '超级鹰密码', '超级鹰软件ID')	#用户中心>>软件ID 生成一个替换 96001
    im = open('b.png', 'rb').read()													#本地图片文件路径 来替换 a.jpg 有时WIN系统须要//
    chaojiying_resp = chaojiying.PostPic(im, 9004)
    print('返回：', chaojiying_resp)											#1902 验证码类型  官方网站>>价格体系 3.4+版 print 后要加()
    # print(chaojiying.PostPic(base64_str, 1902)) #此处为传入 base64代码

    # 从超级鹰返回的数据里获取所有坐标点 {'err_no': 0, 'err_str': 'OK', 'pic_id': '2203715491059120002', 'pic_str': '32,184|75,114|203,183|78,63', 'md5': 'a52b2df54422338dbdcacf3892b4f781'}
    pic_str = chaojiying_resp['pic_str']
    xy_list = pic_str.split('|')

    # 再次分割xy坐标
    new_xy_list = []
    for i in xy_list:
        new_xy_list.append(i.split(','))

    # 点击页面完成验证码内容
    for j in new_xy_list:
        x = location['x'] + int(j[0])
        y = location['y'] + int(j[1])
        ActionChains(browser).move_by_offset(x, y).click().perform()
        ActionChains(browser).move_by_offset(-x, -y).perform()
        print('点击', x, y)
        time.sleep(1)
    print('点击完成')

    # 点击确认完成验证码验证
    browser.find_element(By.XPATH, '/html/body/div[2]/div[2]/div[6]/div/div/div[3]/a').click()
    time.sleep(5)

    # 回到首页
    all_windows = browser.window_handles
    browser.switch_to.window(all_windows[-1])
    browser.find_element(By.XPATH, '//*[@id="app"]/div[1]/div/div[1]/a').click()
    all_windows = browser.window_handles
    browser.switch_to.window(all_windows[-1])

    # 需要爬取的视频BV号 荒野大镖客2：BV1n3411R7CS 空洞骑士：BV1E84y1h7tL 内个asd：BV1G3411d77y
    # BV = 'BV1Xx4y177jN'
    BV = input('需要爬取的视频BV号，如BV1E84y1h7tL：').strip()
    url = 'https://www.bilibili.com/video/' + BV
    # print(url)

    # 头信息
    headers = {
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36 Core/1.94.190.400 QQBrowser/11.5.5240.400',
        'referer': 'https://www.bilibili.com/video/' + BV
    }

    # 访问BV号
    browser.get(url)
    time.sleep(5)
    resp1 = browser.page_source
    # print(type(resp1))
    # with open('b2.html', 'w', encoding='utf-8') as f:
    #     f.write(resp1)
    # print(resp1)

    # 提取标题
    title = re.findall('<h1 title="(.*?)"', resp1)[0]
    print('视频标题：', title)
    print('—' * 100)


    # 判断是否有分p
    p_title = ''
    url2 = ''
    if 'id="multi_page"' in resp1:
        print('有分p')
        ul1 = pq(resp1)('.list-box li a').items()
        index = 1
        p_name_list = []
        for li in ul1:
            print(f'p{index}：', li.attr.title)
            p_name_list.append(li.attr.title)
            index += 1
        p = int(input('请选择一个分p（输入数字）：'))
        p_title = f'p{p}：' + p_name_list[int(p) - 1]
        url2 = f'https://www.bilibili.com/video/{BV}/?p={p}'
    else:
        print('该视频没有分p')
        url2 = f'https://www.bilibili.com/video/{BV}/'
        p_title = 'p1：' + title

    title = re.sub(r'[/\\:*?"<>| ]', '_', title)
    p_title = re.sub(r'[/\\:*?"<>| ]', '_', p_title)

    print('—' * 100)

    # 设置对应分p的url并请求
    # print(url2)
    browser.get(url2)
    time.sleep(5)
    resp2 = browser.page_source

    # 延时后自动退出浏览器
    time.sleep(5)
    browser.quit()

    # 获取信息
    info2 = re.findall('<script>window.__playinfo__=(.*?)</script>', resp2)
    # print(info2)

    # 转成json方便提取
    info2 = json.loads(info2[0])

    # 提取音频视频url
    audio_url = info2['data']['dash']['audio'][0]['baseUrl']
    video_url = info2['data']['dash']['video'][0]['baseUrl']
    # video_url = 'https://xy120x240x45x179xy.mcdn.bilivideo.cn:4483/upgcxcode/07/94/980289407/980289407-1-100022.m4s?e=ig8euxZM2rNcNbdlhoNvNC8BqJIzNbfqXBvEqxTEto8BTrNvN0GvT90W5JZMkX_YN0MvXg8gNEV4NC8xNEV4N03eN0B5tZlqNxTEto8BTrNvNeZVuJ10Kj_g2UB02J0mN0B5tZlqNCNEto8BTrNvNC7MTX502C8f2jmMQJ6mqF2fka1mqx6gqj0eN0B599M=&uipk=5&nbs=1&deadline=1675065273&gen=playurlv2&os=mcdn&oi=3746191873&trid=00005fe151e11d7c44eba072c28b5c666063u&mid=0&platform=pc&upsig=af45c426f0b73e6598fcb677ab180968&uparams=e,uipk,nbs,deadline,gen,os,oi,trid,mid,platform&mcdnid=17000189&bvc=vod&nettype=0&orderid=0,3&buvid=A39C8E9E-793F-0A72-25BB-71A5F8FC100073767infoc&build=0&agrr=1&bw=9308&logo=A0010000'
    # print(audio_url)
    # print(video_url)

    # 创建存放的目录
    try:
        os.makedirs(f'video/{title}/{p_title}/audio')
        os.makedirs(f'video/{title}/{p_title}/video')
    except FileExistsError:
        print('已下载，准备重新下载')

    # 下载音频视频
    print('开始下载')
    audio = requests.get(url=audio_url, headers=headers).content
    video = requests.get(url=video_url, headers=headers).content
    with open(f'video/{title}/{p_title}/audio/{p_title}.mp3', 'wb') as f:
        f.write(audio)
    with open(f'video/{title}/{p_title}/video/{p_title}.mp4', 'wb') as f:
        f.write(video)
    print('下载完毕')

    print('—' * 100)

    # 合并音频视频
    print('使用配置好的ffmpeg速度更快，文件更小，反之')
    isffmpeg = input('如果计算机上已配置好ffmpeg则输入1，否则输入0，请输入：')
    if isffmpeg == '1':
        # 使用配置好ffmpeg
        print('使用ffmpeg合并')
        cmd_id = f'ffmpeg -i video/"{title}"/"{p_title}"/video/"{p_title}.mp4" -i video/"{title}"/"{p_title}"/audio/"{p_title}.mp3" -c:v copy -c:a aac -strict experimental video/"{title}"/"{p_title}"/"{p_title}.mp4"'
        print(cmd_id)
        # subprocess.run(cmd_id, shell=True)
        os.system(cmd_id)
    else:
        # 使用moviepy库进行合并
        print('使用程序自带进行合并')
        # 提取音轨
        # audio = AudioFileClip(f'video\\{title}\\{p_title}\\audio\\{p_title}.mp3')
        audio = moviepy.editor.AudioFileClip(f'video/{title}/{p_title}/audio/{p_title}.mp3')
        # 读入视频
        # video = VideoFileClip(f'video\\{title}\\{p_title}\\video\\{p_title}.mp4')
        video = moviepy.editor.VideoFileClip(f'video/{title}/{p_title}/video/{p_title}.mp4')
        # 将音轨合并到视频中
        # video = video.set_audio(audio)
        video = video.set_audio(audio)
        # 输出
        video.write_videofile(f"video/{title}/{p_title}/{p_title}.mp4")

    print('合并完毕')
    print(f'请在video/{title}/{p_title} 中查看视频')

    current_file_path = os.getcwd()
    os.remove(f'{current_file_path}\\video\\{title}\\{p_title}\\audio\\{p_title}.mp3')
    os.remove(f'{current_file_path}\\video\\{title}\\{p_title}\\video\\{p_title}.mp4')
    os.rmdir(f'{current_file_path}\\video\\{title}\\{p_title}\\audio')
    os.rmdir(f'{current_file_path}\\video\\{title}\\{p_title}\\video')

    print('—' * 100)
    print('程序将在5秒后自动关闭')
    time.sleep(5)
